var yolo = yolo || {};
yolo.debug = yolo.debug || false;

yolo.colorMap = null;
yolo.getHeatColormap = function() {
  if (yolo.colorMap)
    return yolo.colorMap;
  var canvas = document.createElement("canvas");
  var ctx = canvas.getContext('2d');
  if (!ctx) {
    console.log("no ctx");
    return;
  }
  canvas.width = 1;
  canvas.height = 256;
  var gr = ctx.createLinearGradient(0, 0, 1, 256);
  gr.addColorStop(0, 'rgb(0, 30, 150)');
  gr.addColorStop(0.3, 'rgb(30, 180, 0)');
  gr.addColorStop(0.6, 'rgb(255, 255, 0)');
  gr.addColorStop(1.0, 'rgb(255, 0, 0)');
  ctx.fillStyle = gr;
  ctx.fillRect(0, 0, 1, 256);
  cmap = ctx.getImageData(0, 0, 1, 256).data;
  delete gr;
  delete ctx;
  yolo.colorMap = cmap;
  return cmap;
}

yolo.drawHeatGraph = function(id, fileMap) {

  function fillRoundRect(ctx, x, y, w, h, r) {
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.lineTo(x + w - r, y);
    ctx.quadraticCurveTo(x + w, y, x + w, y + r);
    ctx.lineTo(x + w, y + h - r);
    ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
    ctx.lineTo(x + r, y + h);
    ctx.quadraticCurveTo(x, y + h, x, y + h - r);
    ctx.lineTo(x, y + r);
    ctx.quadraticCurveTo(x, y, x + r, y);
    ctx.closePath();
    ctx.fill();
  }

  function fillGradientRect(ctx, rgb, x, y, w, h) {
    ctx.save();
    var r = w;
    var scale = h/w;
    var rscale = 1 / scale;
    ctx.scale(1, scale);
    var gx = (x + w/2);
    var gy = (y + h/2) * rscale;
    var gr = ctx.createRadialGradient(gx, gy, r * 0.3,
                                      gx, gy, r * 0.5);
    gr.addColorStop(0.0, 'rgba(' + rgb + ', 0.7)');
    gr.addColorStop(1.0, 'rgba(' + rgb + ', 0)');
    ctx.fillStyle = gr;
    ctx.fillRect(x, y * rscale, r, r);
    ctx.restore();
  }

  function Point(x, y) {
    this.x = x;
    this.y = y;
  }

  function pointOnCircle(center, r, angle) {
    var x = center.x + r * Math.cos(angle);
    var y = center.y + r * Math.sin(angle);
    return new Point(x, y);
  }

  function fillPie(ctx, center, label,
                  fillStyle, labelStyle,
                  innerRadius, outerRadius,
                  start, end, total) {
    var startRadian = Math.PI * ((2 * start / total + 1.5) % 2);
    var endRadian = Math.PI * ((2 * end / total + 1.5) % 2);

    var p1 = pointOnCircle(center, innerRadius, startRadian);
    var p2 = pointOnCircle(center, outerRadius, startRadian);
    var p3 = pointOnCircle(center, innerRadius, endRadian);
    var p4 = pointOnCircle(center, outerRadius, endRadian);

    ctx.save();
    ctx.beginPath();
    ctx.moveTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.arc(center.x, center.y, outerRadius, startRadian, endRadian, false);
    ctx.lineTo(p4.x, p4.y);
    ctx.arc(center.x, center.y, innerRadius, endRadian, startRadian, true);
    ctx.lineTo(p1.x, p1.y);
    ctx.closePath();
    ctx.fillStyle = fillStyle;
    ctx.fill();
    ctx.restore();

    if (!label || label.length == 0)
      return;

    var gap = Math.abs(endRadian - startRadian);
    if (innerRadius < 50 && gap < 0.08 || gap < 0.06)
      return;

    ctx.save();
    ctx.fillStyle = labelStyle;
    var p = pointOnCircle(center, innerRadius, startRadian);
    ctx.translate(p.x, p.y);
    ctx.rotate(startRadian);
    if (startRadian >= Math.PI * 1.5 || startRadian <= Math.PI * 0.5) {
      ctx.textBaseline = 'top';
      ctx.textAlign = 'left';
      ctx.fillText(label, 3, 0);
    } else {
      ctx.scale(-1, -1);
      ctx.textBaseline = 'bottom';
      ctx.textAlign = 'right';
      ctx.fillText(label, -3, 0);
    }
    ctx.restore();
  }

  var maxLevel = 4;
  function drawPieChart(ctx, cur, center, radius, startValue, max, total, level) {
    var sum = startValue;
    var nextMax = max / 3;
    var maxWidth = 10;
    for (var key in cur.children) {
      var node = cur.children[key];
      for (var k in node.children) {
        var n = node.children[k];
        if (nextMax < n.value)
          nextMax = n.value;
      }
      if (!node.leaf && level + 1 != maxLevel) {
        var w = ctx.measureText(node.name).width + 7;
        if (maxWidth < w)
          maxWidth = w;
      }
    }
    for (var key in cur.children) {
      var node = cur.children[key];
      var label = node.name;
      fillPie(ctx, center, node.name,
              getFillStyle(cmap, node.value, max, 0.7), '#000',
              radius, radius + maxWidth, sum, sum + node.value, total);
      if (level + 1 < maxLevel)
        drawPieChart(ctx, node, center, radius + maxWidth + 1,
                    sum, nextMax, total, level + 1);
      sum += node.value;
    }
  }

  function Trie() {
    function Node(name, value) {
      this.name = name;
      this.value = value;
      this.leaf = true;
      this.children = [];
      this.childrenCount = 0;
    };
    this.root = new Node('/', 0);
    this.add = function(path, value) {
      var ps = path.split('/');
      this.root.value += value;
      var cur = this.root;
      for (var i = 0; i < ps.length; ++i) {
        var segment = ps[i];
        if (segment in cur.children) {
          cur.children[segment].value += value;
        } else {
          cur.children[segment] = new Node(segment, value);
          cur.childrenCount += 1;
        }
        cur.leaf = false;
        cur = cur.children[segment];
      }
    };
  };

  function getFillStyle(cmap, name, max, alpha) {
    var v = Math.floor(255 * (name / max));
    var r = cmap[v*4];
    var g = cmap[v*4+1];
    var b = cmap[v*4+2];
    return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
  }

  function draw(id, fileMap, cmap) {
    var canvas = document.getElementById(id);
    console.log(id, canvas);
    var context = canvas.getContext('2d');
    if (!context) {
      console.log("no context");
      return;
    }

    if (yolo.debug) {
      // reference
      for (var j = 0; j < 255; j++) {
        var r = cmap[j*4];
        var g = cmap[j*4+1];
        var b = cmap[j*4+2];
        context.fillStyle = 'rgb(' + r + ', ' + g + ', ' + b + ')';
        context.fillRect(0, j, 5, 1);
      }
    }

    var trie = new Trie();
    var total = 0;
    for (var i = 0; i < fileMap.length; i++) {
      trie.add(fileMap[i].Key, fileMap[i].Count);
      total += fileMap[i].Count;
    }

    var center = new Point(canvas.width / 2, canvas.height / 2);

    context.font = 'bold 12px sans-serif';
    var w = context.measureText('chrome').width;

    context.textBaseline = 'middle';
    context.textAlign = 'center';
    context.fillStyle = '#000';
    context.fillText('chrome', center.x, center.y);

    context.font = '11px sans-serif';
    var cur = trie.root;

    var max = 0;
    for (var key in cur.children) {
      var node = cur.children[key];
      if (max < node.value)
        max = node.value;
    }
    drawPieChart(context, cur, center, w / 2 + 10, 0, max, total, 0);
  }

  var cmap = yolo.getHeatColormap();
  draw(id, fileMap, cmap);
};
